/* vi:set ts=8 sts=4 sw=4:
 *
 * VIM - Vi IMproved	by Bram Moolenaar
 * 			CodeCheck extension by Birgi Tamersoy
 *				birgitamersoy@gmail.com
 *
 * Do ":help uganda"  in Vim to read copying and usage conditions.
 * Do ":help credits" in Vim to see a list of people who contributed.
 * See README.txt for an overview of the Vim source code.
 */

/*
 * concurrency.c: tools for running threads, etc.
 */

#include "concurrency.h"
#include <assert.h>
#include <stdlib.h>

#ifdef WIN3264
#include <windows.h>
#else
#include <pthread.h>
#endif

thread_status_T create_thread( thread_handle_T handle, void* (*start_function)(void*), void* arg ) 
{
    thread_status_T status = THREAD_OK;

    handle = NULL;

    #ifdef WIN3264
    HANDLE h = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)start_function, arg, 0, NULL );
    handle = (thread_handle_T)h;
    #else
    pthread_t* pt = (pthread_t*)malloc( sizeof(pthread_t) );
    // pthread_attr_t attr;
    int result = pthread_create( pt, NULL, start_function, arg );
    if ( result == 0 ) h = (thread_handle_T)pt;
    #endif

    return status;
}

thread_status_T join_thread( thread_handle_T handle )
{
    thread_status_T status = THREAD_OK;
    
    assert( handle != NULL );

    #ifdef WIN3264
    DWORD result = WaitForSingleObject( handle, INFINITE ); 
    // TODO check result
    #else
    int result = pthread_join( (pthread_t)&handle, NULL );
    // TODO check result
    #endif

    return status;
}

thread_status_T destroy_thread( thread_handle_T handle )
{
  thread_status_T status = THREAD_OK;

  assert( handle != NULL );
  free( handle );

  return status;
}

mutex_status_T create_mutex(mutex_handle_T handle)
{
    handle = NULL;

    mutex_status_T status = MUTEX_OK;

    #ifdef WIN3264
    HANDLE h = CreateMutex( 0, FALSE, 0 ); 
    // TODO check handle result
    handle = (mutex_handle_T)h;
    #else
    pthread_mutex_t* m = (pthread_mutex_t*)malloc( sizeof(pthread_mutex_t) );
    int result = pthread_mutex_init( m, 0 );
    // TODO check result
    if ( result == 0 ) h = (mutex_handle_T)m;
    #endif

    return status;
}

mutex_status_T lock_mutex( mutex_handle_T handle )
{
    mutex_status_T status = MUTEX_OK;

    assert( handle != NULL );

    #ifdef WIN3264
    int result = WaitForSingleObject( handle, INFINITE );
    // TODO check result
    #else
    int result = pthread_mutex_lock( (pthread_mutex_t*)handle );
    // TODO check result
    #endif

    return status;
}

mutex_status_T trylock_mutex( mutex_handle_T handle )
{
    mutex_status_T status = MUTEX_OK;

    assert( handle != NULL );

    #ifdef WIN3264
    #else
    int result = pthread_mutex_trylock((pthread_mutex_t*)handle);
    #endif

    return status;
}

mutex_status_t unlock_mutex( mutex_handle_T handle )
{
    mutex_status_T status = MUTEX_OK;

    assert( handle != NULL );

    #ifdef WIN3264
    int result = ReleaseMutex( handle );
    // TODO check result
    #else
    int result = pthread_mutex_unlock( (pthread_mutex_t*)handle );
    // TODO check result
    #endif

    return status;
}

mutex_status_T destroy_mutex( mutex_handle_T handle )
{
    mutex_status_T status = MUTEX_OK;

    assert( handle != NULL );
    free( handle );

    return status;
}
